import { changeContainerStatusReq, createOneContainerReq } from '@/api/docker'
import { createImagesReq, listImagesReq } from '@/api/images'
import { Document } from '@/generated/graphql'
import { urqlOptions } from '@/plugins/urql'
import { Route, router } from '@/router'
import { useNFS } from '@/stores/nfs'
import { getExtends } from '@/utils/common'
import { runWriteHostsScript } from '@/utils/writeContainerHosts'
import { createClient } from '@urql/vue'
import { isArray } from 'lodash-es'
import { defineStore } from 'pinia'
import { useUserStore } from './auth'

/**
 * docker 相关的hooks
 *
 * docker 容器启动流程
 * 1. 检查是否存在镜像, 不存在的话需要拉取镜像
 * 2. 创建容器，开启gpu
 * 3. 容器中挂载nfs，多容器情况需要在容器中写入host信息
 * 4. 启动所有容器，等待所有容器全部启动完成后进行下一步
 */

interface DockersHook {
  // 镜像名称
  imageName: string
  document?: Document
  currentContainerName?: string
}

export const useDockers = defineStore({
  id: 'docker-hooks',
  persist: {
    storage: sessionStorage
  },
  state: (): DockersHook => ({
    imageName: 'harbor.com/guoshiyin/ttyd:test1'
  }),
  actions: {
    /** 镜像创建(会去远程拉取镜像，异步操作，返回结果的时候镜像不一定拉取完成) */
    async createImage(imageName: string) {
      await createImagesReq(imageName) //触发远端拉取镜像

      const that = this
      async function loop() {
        const image = await that.listImages([imageName])

        if (image.length <= 0) {
          await loop()
        }
      }

      await loop()
    },

    /**列出镜像 */
    async listImages(imageNames: string[]) {
      return await listImagesReq(imageNames)
    },

    /**创建一个容器 */
    async _createContainer(params: {
      containerName: string
      imageName: string
      environment: any
      document: Document
      index: number
    }) {
      const userStore = useUserStore()

      const { containerName, imageName, document, index, environment } = params
     console.log("创建容器参数",containerName);
     
      let ports: Record<string, any> = {}
      let portsBindings: Record<string, any> = {}
      let deviceRequests: Record<string, any>[] = []

      if (/gpu/.test(document?.extends?.PRIVATE.backends[0]?.tag)) {
        deviceRequests = [
          {
            Driver: 'nvidia',
            Count: -1,
            Capabilities: [['gpu']]
          }
        ]
      }
      if (isArray(environment)) {
        environment.forEach((v) => {
          ports[`${v.port}/tcp`] = {}
        })
      }

      const data: any = {
        Image: imageName,
        Tty: true,
        Labels: {
          courseId: document.course?.id,
          documentId: document.id,
          Image: imageName,
          username: userStore?.user?.username
        },
        //端口暴露
        HostConfig: {}
      }

      data['ExposedPorts'] = ports
      data['HostConfig']['PortBindings'] = portsBindings
      data['HostConfig']['DeviceRequests'] = deviceRequests

      // 挂载nfs
      data['Volumes'] = {
        '/opt': {}
      }
      data['Binds'] = ['/opt/data:/opt/data']
    console.log("创建容器参数",data);
    const regex = /^[^,，]+/; // 匹配以非逗号字符开头的正则表达式
    const match = containerName.match(regex);
const result = match ? match[0] : '';

      return createOneContainerReq(result, data)
    },

    /**创建多个容器 */
    async createContainers() {
      const { backends, environment } = getExtends(this.document)
 console.log(backends);
 console.log(environment);
  
      const userStore = useUserStore()
      const client = createClient(urqlOptions)

      //根据hostname的个数来创建容器
      const _hostnames = backends[0].hostname

      // 创建容器所需要的参数
      const containers = _hostnames.map((_x: any, index: number) => {
        const params: Parameters<typeof this._createContainer>[0] = {
          containerName: `${userStore.user?.username}-${this.document!.id}-${_x}`,
          document: this.document as Document,
          //imageName: backends[0].ImageId,
          imageName: this.imageName,
          environment: environment[index],
          index
        }
        return this._createContainer(params)
      })

      const nfsStore = useNFS()
      try {
        //挂载nfs 到openstack实例上面
        await nfsStore.unMountedNFSAll(client)
        await nfsStore.mountedNFS(client)

        // 开始创建容器
        const containerCreates = await Promise.all(containers)
        const containerIds = containerCreates.map((x: any) => x.Id) as string[]
        // 启动容器
        await this.startContainers(containerIds)

        /** 容器本地host文件中写入IP信息 */
        await runWriteHostsScript(containerIds, backends[0].hostname)
      } catch (error: any) {
        await router.replace({ name: Route.COMPETITION })
      }
    },
    /**
     * 容器启动
     */
    async startContainers(containerIds: string[]) {
      const containers = containerIds.map((v) => {
        return changeContainerStatusReq({ id: v, sign: 'start' })
      })

      await Promise.all(containers)
    }
  }
})
